/*******************************************************************************
 * Copyright (c) 2014 Francesco Gabbrielli.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Francesco Gabbrielli - initial API and implementation
 ******************************************************************************/
package it.francescogabbrielli.android.solidalapp;

import java.util.Hashtable;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.os.Handler;
import android.util.Log;

import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.Marker;

public class MapUtils {
	
	private final static Map<Marker, Blinker> BLINKERS = new Hashtable<Marker, Blinker>();
	
	private static class BlinkerStatus {
		int n;
		float[] hues;
//		BitmapDescriptor[] icons;
		BlinkerStatus(float[] hues) {
			this.hues = hues;
//			icons = new BitmapDescriptor[hues.length];
//			for(int i=0; i<hues.length; i++)
//				icons[i] = BitmapDescriptorFactory.defaultMarker(hues[i]);
		}
		float blink() {
			try {return hues[n];} 
			finally {n = (n+1) % hues.length;}
		}
	}
	
	private static class Blinker extends TimerTask {
		
		private final static long DELAY = 500;
		
		private Handler handler;
		private Marker marker;
		private BlinkerStatus status;
		private boolean canceled;
		private Timer timer;
		private long start;
		private long duration;
		private float lastHue;
		
		Blinker(Context context, Marker marker, long interval, long duration, float[] hues) {
			this.handler = new Handler(context.getMainLooper());
			this.marker = marker;
			status = new BlinkerStatus(hues);
			timer = new Timer();
			start = System.currentTimeMillis();
			this.duration = duration;
			lastHue = hues[hues.length-1];
			
			// start blinking after some delay
			timer.scheduleAtFixedRate(this, DELAY, interval);
			
		}
		
		@Override
		public boolean cancel() {
			canceled = true;
			boolean ret = super.cancel();
			timer.cancel();
			return ret;
		}
		
		@Override
		public void run() {
			if(System.currentTimeMillis()-start >= duration) {
				synchronized (BLINKERS) {
					BLINKERS.remove(this);
					cancel();
				}
				handler.post(new Runnable() {
					@Override
					public void run() {
						changeIcon(marker, lastHue);
					}
				});
			} else {
				handler.post(new Runnable() {
					@Override
					public void run() {
						if (!canceled)
							changeIcon(marker, status.blink());
					}
				});
			}
		}
	}
	
	/**
	 * Blink a marker cycling through a spectrum of different hues
	 * 
	 * @param context 
	 * 					the app context
	 * @param marker
	 * 					the marker to blink
	 * @param interval
	 * 					how long each hue should display
	 * @param duration
	 * 					total duration of the blinking
	 * @param hues
	 * 					the hues
	 */
	public static void startBlinkIcon(Context context, Marker marker, long interval, long duration, float[] hues) {
		synchronized (BLINKERS) {
			stopBlinkIcon(marker, hues[hues.length-1]);
			BLINKERS.put(marker, new Blinker(context, marker, interval, duration, hues));
		}
	}

	/**
	 * Stop blinking a marker
	 * 
	 * @param marker
	 * 					the marker to stop
	 * @param hue
	 * 					the final hue to set the marker icon to
	 * 
	 */
	public static void stopBlinkIcon(Marker marker, float hue) {
		if(marker!=null && marker.isVisible())
			synchronized (BLINKERS) {
				Blinker blinker = BLINKERS.remove(marker);
				if(blinker!=null)
					blinker.cancel();
				if(hue>=0)
					changeIcon(marker, hue);
			}
	}
	
	public static void stopBlinkIcon(Marker marker) {
		stopBlinkIcon(marker, -1);
	}
	
	/**
	 * Change icon preserving info window
	 * 
	 * @param marker
	 * 
	 * @param icon
	 * 
	 */
	public static void changeIcon(Marker marker, float hue) {
		try {
			boolean info = marker.isInfoWindowShown();
			marker.setIcon(BitmapDescriptorFactory.defaultMarker(hue));
			if(info)
				marker.showInfoWindow();
		} catch(Exception e) {
			Log.e(SolidalApp.TAG, "Error changing icon: "+hue, e);
		}
	}

}
